﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;

namespace Ruandao.Setting
{
    using Ruandao.MiniAccess;
    using Ruandao.Setting.EntityAccess;
    using System.Web.Security;
    using Ruandao.HostServer;

    /// <summary>
    /// 管理应用程序中的设置数据的静态工具类，所提供的静态方法使用了实现IOptionData的泛型参数。
    /// 该类所操作的数据库根据映射文件中的Setting提供者指定，数据库处理时所需要的SettingContext和UserGuid分别在AppContext
    /// 和UserContext中获取。
    /// </summary>
    [Serializable]
    public class OptionData
    {
        private Dictionary<string, object> dict = new Dictionary<string, object>();

        string optionName = "";
        public OptionData(string optionName)
        {
            this.optionName = optionName;
        }

        public T GetProperty<T>( string property )
        {
            if (dict.ContainsKey(property))
                return (T)dict[property];
            else
                return default(T);
        }

        public void SetProperty<T>(string property, T value)
        {
            if (!dict.ContainsKey(property))
            {
                dict.Add(property, value);
            }
            else dict[property] = value;
        }

        static public OptionData GetInitialValue(string optionName)
        {
            return InitialSettings.Instance.GetInitialValue(optionName);
        }


        /// <summary>
        /// 获取系统设置，不搜索默认设置，如果没有设定值则返回null。
        /// </summary>
        public OptionData FetchSystem()
        {
            string wareName = SiteWare.Current.Ware.WareName;
            SettingEntity entity = SettingEntity.FetchByWareName_Name(wareName, this.optionName);
            if (entity == null)
            {
                return null;
            }

            return GetOptionObject(entity.Data);
        }

        /// <summary>
        /// 获取当前用户的设置数据，不搜索系统设置和默认设置，如果用户没有设定值则返回null。
        /// </summary>
        public OptionData Fetch()
        {
            if (Membership.GetUser() == null) return null;
            Guid userGuid = (Guid)Membership.GetUser().ProviderUserKey;
            return Fetch(userGuid);
        }

        /// <summary>
        /// 获取指定用户的设置数据，不搜索系统设置和默认设置，如果用户没有设定值则返回null。
        /// </summary>
        /// <param name="userGuid">指定用户。</param>
        /// <returns></returns>
        public OptionData Fetch(Guid userGuid)
        {
            string wareName = SiteWare.Current.Ware.WareName;
            SettingEntity entity = SettingEntity.FetchByWareName_Name(wareName, this.optionName);
            if (entity == null)
            {
                return null;
            }
            UserSettingEntity user = UserSettingEntity.Fetch(userGuid, entity.Id);
            if (user == null)
            {
                return null;

            }
            return GetOptionObject(user.Data);
        }

        /// <summary>
        /// 获取当前用户可用的设置数据，依次查找用户设置、系统设置和默认设置。
        /// </summary>
        public OptionData CurrentOption()
        {
            if (Membership.GetUser() == null)
            {
                OptionData option = FetchSystem();
                if (option == null)
                {
                    option = GetInitialValue(this.optionName);
                }

                return option;
            }
            Guid userGuid = (Guid)Membership.GetUser().ProviderUserKey;
            return CurrentOption(userGuid);
        }

        /// <summary>
        /// 获取指定用户可用的设置数据，依次查找用户设置、系统设置和默认设置。
        /// </summary>
        /// <param name="userGuid">指定用户。</param>
        /// <returns></returns>
        public OptionData CurrentOption(Guid userGuid)
        {
            OptionData option = Fetch(userGuid);
            if (option != null) return option;

            option = FetchSystem();
            if (option == null)
            {
                option = GetInitialValue(this.optionName);
            }
            return option;
        }
        /// <summary>
        /// 复位系统设置，即用原始设置覆盖系统设置。
        /// </summary>
        public void ResetSystem()
        {
            Write(GetInitialValue(this.optionName));
        }

        /// <summary>
        /// 复位当前用户的设置，即将系统的设置复制给当前用户。
        /// </summary>
        public void Reset()
        {
            Guid userGuid = (Guid)Membership.GetUser().ProviderUserKey;
            Reset(userGuid);
        }

        /// <summary>
        /// 复位指定用户的设置，即将系统的设置复制给指定用户。
        /// </summary>
        public void Reset(Guid userGuid)
        {
            OptionData option = FetchSystem();
            if (option == null)
            {
                option = GetInitialValue(this.optionName);
            }
            Write(option, userGuid);
        }

        /// <summary>
        /// 清除当前用户的设置,即直接使用系统设置。
        /// </summary>
        public void Delete()
        {
            Guid userGuid = (Guid)Membership.GetUser().ProviderUserKey;
            Delete(userGuid);
        }

        /// <summary>
        /// 清除指定用户的设置,即直接使用系统设置。
        /// </summary>
        /// <param name="userGuid">指定用户。</param>
        public void Delete(Guid userGuid)
        {
            //得到settingId 
            string wareName = SiteWare.Current.Ware.WareName;
            SettingEntity entity = SettingEntity.FetchByWareName_Name(wareName,this.optionName);
            //判断有无得到数据
            if (entity == null)
            {
                return;
            }

            //判断有无该用户的用户设置
            UserSettingEntity user = UserSettingEntity.Fetch(userGuid, entity.Id);
            if (user == null)
            {
                return;
            }
            UserSettingEntity.Delete(userGuid, entity.Id);
        }

        /// <summary>
        /// 保存系统设置。
        /// </summary>
        public void SaveSystem()
        {
            Write(this);
        }

        /// <summary>
        /// 保存设置数据到当前用户。
        /// </summary>
        public void Save()
        {
            if (Membership.GetUser()==null) return;
            Guid userGuid = (Guid)Membership.GetUser().ProviderUserKey;
            Write(this, userGuid);
        }

        /// <summary>
        /// 保存设置数据到指定用户。
        /// </summary>
        /// <param name="option">设置数据。</param>
        /// <param name="userGuid">指定用户。</param>
        /// <returns></returns>
        public void Save(Guid userGuid)
        {
            Write(this, userGuid);
        }

        // ==== private method ====

        static void Write(OptionData option)
        {
            string wareName = SiteWare.Current.Ware.WareName;
            SettingEntity entity = SettingEntity.FetchByWareName_Name(wareName, option.optionName);
            if (entity == null)
            {
                entity = new SettingEntity();
                entity.WareName = wareName;
                entity.Name = option.optionName;
            }

            entity.Data = GetOptionBytes(option);
            entity.Save();
        }

        static void Write(OptionData option, Guid userGuid)
        {
            string wareName = SiteWare.Current.Ware.WareName;
            SettingEntity entity = SettingEntity.FetchByWareName_Name(wareName, option.optionName);
            // 并非数据库中总是存在选项的设定值，最初所有的设定值在数据中都可以不存在，
            // 在运行过程中，根据需要才逐步保存到数据库中，以供系统管理员和用户定制。
            if (entity == null)
            {
                entity = new SettingEntity();
                entity.Name = option.optionName;
                entity.WareName = wareName;

                entity.Data = GetOptionBytes(GetInitialValue(option.optionName));

                entity.Save();
            }

            UserSettingEntity userEntity = UserSettingEntity.Fetch(userGuid, entity.Id);
            if (userEntity == null)
            {
                userEntity = new UserSettingEntity();
                userEntity.SettingId = entity.Id;
                userEntity.UserGuid = userGuid;
            }
            userEntity.Data = GetOptionBytes(option);
            userEntity.Save();
        }


        // ==== 下面的函数是用来序列化和反序列化设置对象。  =====

        /// <summary>
        /// 用于把选项对象序列化成选项数据字节。
        /// </summary>
        /// <param name="optionData"></param>
        /// <returns></returns>
        static byte[] GetOptionBytes(object option)
        {
            MemoryStream stream = new MemoryStream();
            new BinaryFormatter().Serialize(stream, option);
            stream.Close();
            return stream.ToArray();
        }

        /// <summary>
        /// 用于把选项数据字节反序列化选项对象
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        static OptionData GetOptionObject(Byte[] bytes)
        {
            MemoryStream stream = new MemoryStream(bytes);
            return (OptionData)new BinaryFormatter().Deserialize(stream);
        }
    }
}
